package com.example.aicodemother.core.builder;

import cn.hutool.core.util.RuntimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.concurrent.TimeUnit;

/**
 * Vue项目构建器
 * <p>
 * 用于异步构建Vue项目，包括安装依赖和打包构建
 */
@Slf4j
@Component
public class VueProjectBuilder {

    /**
     * 异步构建Vue项目
     *
     * @param projectPath 项目路径
     */
    public void buildProjectAsync(String projectPath) {
        Thread.ofVirtual().name("vue-builder-" + System.currentTimeMillis())
                .start(() -> {
                    try {
                        buildProject(projectPath);
                    } catch (Exception e) {
                        log.error("异步构建构建vue项目失败{}", e.getMessage(), e);
                    }
                });
    }

    /**
     * 构建Vue项目
     * <p>
     * 包括检查项目目录、安装依赖、打包构建和验证构建结果
     *
     * @param projectPath 项目路径
     * @return 构建是否成功
     */
    public boolean buildProject(String projectPath) {
        File projectDir = new File(projectPath);
        if (!projectDir.exists() || !projectDir.isDirectory()) {
            log.error("项目目录不存在或者不是目录：{}", projectPath);
            return false;
        }
        //检查是否有package.json文件
        File packageJson = new File(projectDir, "package.json");
        if (!packageJson.exists()) {
            log.error("项目目录下不存在package.json文件：{}", projectPath);
            return false;
        }
        log.info("开始构建项目：{}", projectPath);
        if (!executeNpmInstall(projectDir)) {
            log.error("npm install 失败");
            return false;
        }
        if (!executeNpmBuild(projectDir)) {
            log.error("npm build 构建失败");
            return false;
        }
        //验证dist目录是否存在
        File distDir = new File(projectDir, "dist");
        if (!distDir.exists()) {
            log.error("项目构建失败，目录下不存在dist目录：{}", projectPath);
            return false;
        }
        log.info("项目构建成功：{}", projectPath);
        return true;
    }

    /**
     * 执行npm install命令安装依赖
     *
     * @param projectDir 项目目录
     * @return 执行是否成功
     */
    private boolean executeNpmInstall(File projectDir) {
        log.info("开始执行 npm install");
        String command = String.format("%s install", buildCommand("npm"));
        return executeCommand(projectDir, command, 300);
    }

    /**
     * 执行npm run build命令构建项目
     *
     * @param projectDir 项目目录
     * @return 执行是否成功
     */
    private boolean executeNpmBuild(File projectDir) {
        log.info("开始执行 npm build");
        String command = String.format("%s run build", buildCommand("npm"));
        return executeCommand(projectDir, command, 180);
    }

    /**
     * 判断操作系统是否为Windows
     *
     * @return 是否为Windows系统
     */
    private boolean isWindows() {
        return System.getProperty("os.name").toLowerCase().startsWith("win");
    }

    /**
     * 根据操作系统构建命令
     * <p>
     * Windows系统添加.cmd后缀
     *
     * @param baseCommand 基础命令
     * @return 适配当前系统的命令
     */
    private String buildCommand(String baseCommand) {
        if (isWindows()) {
            return baseCommand + ".cmd";
        }
        return baseCommand;
    }

    /**
     * 执行命令
     *
     * @param workingDir     工作目录
     * @param command        命令字符串
     * @param timeoutSeconds 超时时间（秒）
     * @return 是否执行成功
     */
    private boolean executeCommand(File workingDir, String command, int timeoutSeconds) {
        try {
            log.info("在目录 {} 中执行命令: {}", workingDir.getAbsolutePath(), command);
            Process process = RuntimeUtil.exec(
                    null,
                    workingDir,
                    command.split("\\s+") // 命令分割为数组
            );
            // 等待进程完成，设置超时
            boolean finished = process.waitFor(timeoutSeconds, TimeUnit.SECONDS);
            if (!finished) {
                log.error("命令执行超时（{}秒），强制终止进程", timeoutSeconds);
                process.destroyForcibly();
                return false;
            }
            int exitCode = process.exitValue();
            if (exitCode == 0) {
                log.info("命令执行成功: {}", command);
                return true;
            } else {
                log.error("命令执行失败，退出码: {}", exitCode);
                return false;
            }
        } catch (Exception e) {
            log.error("执行命令失败: {}, 错误信息: {}", command, e.getMessage());
            return false;
        }
    }
}
